package com.xiaoma.service.impl;

import com.xiaoma.mapper.FileMapper;
import com.xiaoma.mapper.SliceFileMapper;
import com.xiaoma.pojo.FileUploadDTO;
import com.xiaoma.pojo.FileUploadRequestDTO;
import com.xiaoma.service.FileService;
import com.xiaoma.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
@Slf4j
public class FileServiceImpl implements FileService {


  @Autowired
  private FilePathUtil filePathUtil;

  @Autowired
  FileMapper fileMapper;

  @Autowired
  SliceFileMapper sliceFileMapper;

  @Value("${upload.chunkSize}")
  private long defaultChunkSize;

    /**
     * 上传文件
   * @param param
     * @return
     * @throws IOException
   */
  @Override
  public FileUploadDTO upload(FileUploadRequestDTO param) throws IOException {
    param.setPath(FileUtil.withoutHeadAndTailDiagonal(param.getPath()));
    String md5 = FileMD5Util.getFileMD5(param.getFile());
    param.setMd5(md5);
    param.setFlag(false);
    //插入大文件表
    FileUploadRequestDTO fileUploadRequestDTO = fileMapper.queryByName(param.getName());
    fileUploadRequestDTO.setChunks(param.getChunks());
    fileMapper.updateByName(fileUploadRequestDTO.setFlag(false));

    String filePath = filePathUtil.getPath(param);
    File targetFile = new File(filePath);
    if (!targetFile.exists()) {
      targetFile.mkdirs();
    }
    String path = filePath + FileConstant.FILE_SEPARATORCHAR + param.getFile().getOriginalFilename() + md5;
    if (param.getChunk() == null) {
      path = filePath + FileConstant.FILE_SEPARATORCHAR + param.getFile().getOriginalFilename();
    }
    FileOutputStream out = new FileOutputStream(path);
    out.write(param.getFile().getBytes());
    out.flush();
    FileUtil.close(out);
    if (param.getChunk() != null) {
      split(param);
      //插入小文件表
      sliceFileMapper.insert(param);
    }
    List<Integer> count = sliceFileMapper.count(param);
    if (count.stream().count() == param.getChunks()) {
//      System.out.println("小文件count："+count.stream().count()+"----------文件总片数"+param.getChunks());
      boolean b = fileMapper.updateByName(fileUploadRequestDTO.setFlag(true));
    }
    return FileUploadDTO.builder().path(path).uploadComplete(true).build();
  }

    /**
     * 合并文件
   * @param param
     * @return
     */
  public boolean split(FileUploadRequestDTO param) {
    //合并
    RandomAccessFile accessTmpFile = null;
    try {
      File tmpFile = createTmpFile(param);
      accessTmpFile = new RandomAccessFile(tmpFile, "rw");
      //这个必须与前端设定的值一致
      long chunkSize = Objects.isNull(param.getChunkSize()) ? defaultChunkSize * 1024 * 1024
              : param.getChunkSize();
      long offset = chunkSize * param.getChunk();
      //定位到该分片的偏移量
      accessTmpFile.seek(offset);
      //写入该分片数据
      accessTmpFile.write(param.getFile().getBytes());
    } catch (IOException e) {
      log.error(e.getMessage(), e);
    } finally {
      FileUtil.close(accessTmpFile);
      return true;
    }
  }

  /**
   * 创建文件
   * @param param
   * @return
   */
  protected File createTmpFile(FileUploadRequestDTO param) {

    FilePathUtil filePathUtil = SpringContextHolder.getBean(FilePathUtil.class);
    param.setPath(FileUtil.withoutHeadAndTailDiagonal(param.getPath()));
    String fileName = param.getFile().getOriginalFilename();
    String uploadDirPath = filePathUtil.getPath(param);
    String tempFileName = fileName;
    File tmpDir = new File(uploadDirPath);
    File tmpFile = new File(uploadDirPath, tempFileName);
    if (!tmpDir.exists()) {
      tmpDir.mkdirs();
    }
    return tmpFile;
  }

  /**
   * 检查MD5
   * @param param
   * @return
   */
  @Override
  public FileUploadDTO checkFileMd5(FileUploadRequestDTO param) {
    ArrayList<Integer> list = new ArrayList<>();
    Integer chunks = null;
    FileUploadRequestDTO flag = fileMapper.queryByMd5(param);
    FileUploadRequestDTO fileUploadRequestDTO = fileMapper.queryByName(param.getName());
    if(fileUploadRequestDTO!=null){
       chunks = fileUploadRequestDTO.getChunks();
    }
    List<Integer> count = sliceFileMapper.count(param);
    if (flag != null) {
      if (!(chunks==count.stream().count())){
        for (int i = 0; i <chunks ; i++) {
          list.add(i);
        }
        for (int i = 0; i < count.size(); i++) {
          list.remove(count.get(i));
        }
        return FileUploadDTO.builder().code(FileCheckMd5Status.FILE_UPLOAD_SOME.getValue())
                .missChunks(list).build();
      }
        else {
        return FileUploadDTO.builder().code(FileCheckMd5Status.FILE_UPLOADED.getValue()).build();
      }
    }
    else {
       fileMapper.insertFile(param);
       return FileUploadDTO.builder().code(FileCheckMd5Status.FILE_NO_UPLOAD.getValue()).build();
     }
  }
}
